package edu.pitt.myptm.transactionmanger;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Random;

import edu.pitt.myptm.CommandFactory;
import edu.pitt.myptm.MyCommand;

public class TransactionManager {
	private ArrayList<String> fileList = new ArrayList<String>();
	private ArrayList<BufferedReader> readerList = new ArrayList<BufferedReader>();

	public static final int ROUND_ROBIN = 1;
	public static final int RANDOM = 2;
	private int mode = ROUND_ROBIN;
	int currentIndex = 0;
	int timestampIndex = 0;
	int remainingCount = 0;
	int fileCount = 0;
	int finishedCount = 0;
	int[] filearray;
	private HashSet<Integer> finishedIndex;

	public void addFile(String file) {
		fileList.add(file);
	}

	public void switchToRandom() {
		this.mode = RANDOM;
	}

	public void switchToRB() {
		this.mode = ROUND_ROBIN;
	}

	public void init() throws FileNotFoundException {
		for (int i = 0; i < fileList.size(); i++) {
			String file = fileList.get(i);
			BufferedReader reader = new BufferedReader(new FileReader(file));
			readerList.add(reader);
		}
		if (mode == ROUND_ROBIN) {
			currentIndex = 0;
			finishedIndex = new HashSet<Integer>();
			remainingCount = readerList.size();
			fileCount = readerList.size();
		} else {
			// currentIndex = 0;
			// finishedIndex = new HashSet<Integer>();
			// remainingCount = readerList.size();
			fileCount = readerList.size();
			finishedCount = 0;
			filearray = new int[fileCount];
			for (int i = 0; i < fileCount; i++) {
				filearray[i]= i;
			}
		}
	}

	public MyCommand loadNext() throws IOException {
		if (mode == ROUND_ROBIN) {
			return loadRNext();
		} else {
			return loadRandNext();
		}
	}

	private long seed;
	private Random rand;

	public void setSeed(long seed) {
		this.seed = seed;
		rand = new Random();
		rand.setSeed(seed);
	}

	public void swap(int i, int j) {
		int temp = filearray[i];
		filearray[i] = filearray[j];
		filearray[j] = temp;
	}

	public MyCommand loadRandNext() throws IOException {
		if (finishedCount == fileCount)
			return null;
		timestampIndex++;
		BufferedReader reader;
		String line = null;
		while (line == null) {
			int next;
			if (finishedCount == fileCount - 1) {
				next = finishedCount;
			} else {
				next = rand.nextInt(fileCount - finishedCount);
				next = next + finishedCount;
			}
			currentIndex = filearray[next];
			reader = readerList.get(currentIndex);
			line = reader.readLine();
			if (line == null) {
				if (finishedCount != fileCount - 1) {
					swap(finishedCount, next);
				} 
				finishedCount++;
				if(finishedCount == fileCount) {
					return null;
				} 
			} else {
				return CommandFactory.makeCommand(line, next, timestampIndex);
			}
		}
		return null;
	}

	public MyCommand loadRNext() throws IOException {
		// int length = readerList.size();
		// boolean isEnding = false;
		// if(finishedIndex.size()==length) return null;
		// if(finishedIndex.size()==length-1) isEnding = true;
		if (remainingCount == 0)
			return null;
		BufferedReader reader;
		while (finishedIndex.contains(currentIndex)) {
			currentIndex++;
			currentIndex = currentIndex % fileCount; // If the index goes out of
														// boundary, set it back
		}
		String line = null;
		int indexid = currentIndex;
		int loopCount = 0;
		while (line == null) {
			reader = readerList.get(currentIndex);
			indexid = currentIndex;
			line = reader.readLine();
			if (line == null) {
				if (!finishedIndex.contains(currentIndex)) {
					finishedIndex.add(currentIndex);
					remainingCount--;
				}
			}
			currentIndex++;
			currentIndex = currentIndex % fileCount;
			// if(line == null && loopCount > ) return null;
			if (remainingCount == 0)
				return null;
		}
		timestampIndex++;
		return CommandFactory.makeCommand(line, indexid, timestampIndex);
	}
}
